/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: sw=2 ts=8 et : *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"Layers.h"#include<algorithm> // for max, min#include"apz/src/AsyncPanZoomController.h"#include"CompositableHost.h" // for CompositableHost#include"ImageContainer.h" // for ImageContainer, etc#include"ImageLayers.h" // for ImageLayer#include"LayerSorter.h" // for SortLayersBy3DZOrder#include"LayersLogging.h" // for AppendToString#include"LayerUserData.h"#include"ReadbackLayer.h" // for ReadbackLayer#include"UnitTransforms.h" // for ViewAs#include"gfxEnv.h"#include"gfxPlatform.h" // for gfxPlatform#include"gfxPrefs.h"#include"gfxUtils.h" // for gfxUtils, etc#include"gfx2DGlue.h"#include"mozilla/DebugOnly.h" // for DebugOnly#include"mozilla/IntegerPrintfMacros.h"#include"mozilla/Telemetry.h" // for Accumulate#include"mozilla/ToString.h"#include"mozilla/gfx/2D.h" // for DrawTarget#include"mozilla/gfx/BaseSize.h" // for BaseSize#include"mozilla/gfx/Matrix.h" // for Matrix4x4#include"mozilla/gfx/Polygon.h" // for Polygon#include"mozilla/layers/AnimationHelper.h"#include"mozilla/layers/AsyncCanvasRenderer.h"#include"mozilla/layers/BSPTree.h" // for BSPTree#include"mozilla/layers/CompositableClient.h" // for CompositableClient#include"mozilla/layers/Compositor.h" // for Compositor#include"mozilla/layers/CompositorTypes.h"#include"mozilla/layers/LayerManagerComposite.h" // for LayerComposite#include"mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper#include"mozilla/layers/LayersMessages.h" // for TransformFunction, etc#include"mozilla/layers/LayersTypes.h" // for TextureDumpMode#include"mozilla/layers/PersistentBufferProvider.h"#include"mozilla/layers/ShadowLayers.h" // for ShadowableLayer#include"nsAString.h"#include"nsCSSValue.h" // for nsCSSValue::Array, etc#include"nsDisplayList.h" // for nsDisplayItem#include"nsPrintfCString.h" // for nsPrintfCString#include"nsStyleStruct.h" // for nsTimingFunction, etc#include"protobuf/LayerScopePacket.pb.h"#include"mozilla/Compression.h"#include"TreeTraversal.h" // for ForEachNode#include<list>#include<set>uint8_tgLayerManagerLayerBuilder;namespacemozilla{namespacelayers{FILE*FILEOrDefault(FILE*aFile){returnaFile?aFile:stderr;}typedefFrameMetrics::ViewIDViewID;usingnamespacemozilla::gfx;usingnamespacemozilla::Compression;//--------------------------------------------------// LayerManager/* static */mozilla::LogModule*LayerManager::GetLog(){staticLazyLogModulesLog("Layers");returnsLog;}FrameMetrics::ViewIDLayerManager::GetRootScrollableLayerId(){if(!mRoot){returnFrameMetrics::NULL_SCROLL_ID;}LayerMetricsWrapperlayerMetricsRoot=LayerMetricsWrapper(mRoot);LayerMetricsWrapperrootScrollableLayerMetrics=BreadthFirstSearch<ForwardIterator>(layerMetricsRoot,[](LayerMetricsWrapperaLayerMetrics){returnaLayerMetrics.Metrics().IsScrollable();});returnrootScrollableLayerMetrics.IsValid()?rootScrollableLayerMetrics.Metrics().GetScrollId():FrameMetrics::NULL_SCROLL_ID;}LayerMetricsWrapperLayerManager::GetRootContentLayer(){if(!mRoot){returnLayerMetricsWrapper();}LayerMetricsWrapperroot(mRoot);returnBreadthFirstSearch<ForwardIterator>(root,[](LayerMetricsWrapperaLayerMetrics){returnaLayerMetrics.Metrics().IsRootContent();});}already_AddRefed<DrawTarget>LayerManager::CreateOptimalDrawTarget(constgfx::IntSize&aSize,SurfaceFormataFormat){returngfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(aSize,aFormat);}already_AddRefed<DrawTarget>LayerManager::CreateOptimalMaskDrawTarget(constgfx::IntSize&aSize){returnCreateOptimalDrawTarget(aSize,SurfaceFormat::A8);}already_AddRefed<DrawTarget>LayerManager::CreateDrawTarget(constIntSize&aSize,SurfaceFormataFormat){returngfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(aSize,aFormat);}already_AddRefed<PersistentBufferProvider>LayerManager::CreatePersistentBufferProvider(constmozilla::gfx::IntSize&aSize,mozilla::gfx::SurfaceFormataFormat){RefPtr<PersistentBufferProviderBasic>bufferProvider=PersistentBufferProviderBasic::Create(aSize,aFormat,gfxPlatform::GetPlatform()->GetPreferredCanvasBackend());if(!bufferProvider){bufferProvider=PersistentBufferProviderBasic::Create(aSize,aFormat,gfxPlatform::GetPlatform()->GetFallbackCanvasBackend());}returnbufferProvider.forget();}already_AddRefed<ImageContainer>LayerManager::CreateImageContainer(ImageContainer::Modeflag){RefPtr<ImageContainer>container=newImageContainer(flag);returncontainer.forget();}boolLayerManager::AreComponentAlphaLayersEnabled(){returngfxPrefs::ComponentAlphaEnabled();}/*static*/voidLayerManager::LayerUserDataDestroy(void*data){deletestatic_cast<LayerUserData*>(data);}UniquePtr<LayerUserData>LayerManager::RemoveUserData(void*aKey){UniquePtr<LayerUserData>d(static_cast<LayerUserData*>(mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));returnd;}//--------------------------------------------------// LayerLayer::Layer(LayerManager*aManager,void*aImplData):mManager(aManager),mParent(nullptr),mNextSibling(nullptr),mPrevSibling(nullptr),mImplData(aImplData),mCompositorAnimationsId(0),mUseTileSourceRect(false),#ifdef DEBUGmDebugColorIndex(0),#endifmAnimationGeneration(0){}Layer::~Layer(){}voidLayer::EnsureAnimationsId(){if(!mCompositorAnimationsId){mCompositorAnimationsId=AnimationHelper::GetNextCompositorAnimationsId();}}Animation*Layer::AddAnimation(){// Here generates a new id when the first animation is added and// this id is used to represent the animations in this layer.EnsureAnimationsId();MOZ_LAYERS_LOG_IF_SHADOWABLE(this,("Layer::Mutated(%p) AddAnimation with id=%"PRIu64,this,mCompositorAnimationsId));MOZ_ASSERT(!mPendingAnimations,"should have called ClearAnimations first");Animation*anim=mAnimations.AppendElement();Mutated();returnanim;}voidLayer::ClearAnimations(){mPendingAnimations=nullptr;if(mAnimations.IsEmpty()&&mAnimationData.IsEmpty()){return;}MOZ_LAYERS_LOG_IF_SHADOWABLE(this,("Layer::Mutated(%p) ClearAnimations",this));mAnimations.Clear();mAnimationData.Clear();Mutated();}Animation*Layer::AddAnimationForNextTransaction(){MOZ_ASSERT(mPendingAnimations,"should have called ClearAnimationsForNextTransaction first");Animation*anim=mPendingAnimations->AppendElement();returnanim;}voidLayer::ClearAnimationsForNextTransaction(){// Ensure we have a non-null mPendingAnimations to mark a future clear.if(!mPendingAnimations){mPendingAnimations=newAnimationArray;}mPendingAnimations->Clear();}voidLayer::SetCompositorAnimations(constCompositorAnimations&aCompositorAnimations){MOZ_LAYERS_LOG_IF_SHADOWABLE(this,("Layer::Mutated(%p) SetCompositorAnimations with id=%"PRIu64,this,mCompositorAnimationsId));mAnimations=aCompositorAnimations.animations();mCompositorAnimationsId=aCompositorAnimations.id();mAnimationData.Clear();AnimationHelper::SetAnimations(mAnimations,mAnimationData,mBaseAnimationStyle);Mutated();}voidLayer::StartPendingAnimations(constTimeStamp&aReadyTime){ForEachNode<ForwardIterator>(this,[&aReadyTime](Layer*layer){boolupdated=false;for(size_tanimIdx=0,animEnd=layer->mAnimations.Length();animIdx<animEnd;animIdx++){Animation&anim=layer->mAnimations[animIdx];// If the animation is play-pending, resolve the start time.// This mirrors the calculation in Animation::StartTimeFromReadyTime.if(anim.startTime().type()==MaybeTimeDuration::Tnull_t&&!anim.originTime().IsNull()&&!anim.isNotPlaying()){TimeDurationreadyTime=aReadyTime-anim.originTime();anim.startTime()=anim.playbackRate()==0?readyTime:readyTime-anim.holdTime().MultDouble(1.0/anim.playbackRate());updated=true;}}if(updated){layer->Mutated();}});}voidLayer::SetAsyncPanZoomController(uint32_taIndex,AsyncPanZoomController*controller){MOZ_ASSERT(aIndex<GetScrollMetadataCount());mApzcs[aIndex]=controller;}AsyncPanZoomController*Layer::GetAsyncPanZoomController(uint32_taIndex)const{MOZ_ASSERT(aIndex<GetScrollMetadataCount());#ifdef DEBUGif(mApzcs[aIndex]){MOZ_ASSERT(GetFrameMetrics(aIndex).IsScrollable());}#endifreturnmApzcs[aIndex];}voidLayer::ScrollMetadataChanged(){mApzcs.SetLength(GetScrollMetadataCount());}voidLayer::ApplyPendingUpdatesToSubtree(){ForEachNode<ForwardIterator>(this,[](Layer*layer){layer->ApplyPendingUpdatesForThisTransaction();});// Once we're done recursing through the whole tree, clear the pending// updates from the manager.Manager()->ClearPendingScrollInfoUpdate();}boolLayer::IsOpaqueForVisibility(){returnGetEffectiveOpacity()==1.0f&&GetEffectiveMixBlendMode()==CompositionOp::OP_OVER;}boolLayer::CanUseOpaqueSurface(){// If the visible content in the layer is opaque, there is no need// for an alpha channel.if(GetContentFlags()&CONTENT_OPAQUE)returntrue;// Also, if this layer is the bottommost layer in a container which// doesn't need an alpha channel, we can use an opaque surface for this// layer too. Any transparent areas must be covered by something else// in the container.ContainerLayer*parent=GetParent();returnparent&&parent->GetFirstChild()==this&&parent->CanUseOpaqueSurface();}// NB: eventually these methods will be defined unconditionally, and// can be moved into Layers.hconstMaybe<ParentLayerIntRect>&Layer::GetLocalClipRect(){if(HostLayer*shadow=AsHostLayer()){returnshadow->GetShadowClipRect();}returnGetClipRect();}constLayerIntRegion&Layer::GetLocalVisibleRegion(){if(HostLayer*shadow=AsHostLayer()){returnshadow->GetShadowVisibleRegion();}returnGetVisibleRegion();}Matrix4x4Layer::SnapTransformTranslation(constMatrix4x4&aTransform,Matrix*aResidualTransform){if(aResidualTransform){*aResidualTransform=Matrix();}if(!mManager->IsSnappingEffectiveTransforms()){returnaTransform;}Matrixmatrix2D;if(aTransform.CanDraw2D(&matrix2D)&&!matrix2D.HasNonTranslation()&&matrix2D.HasNonIntegerTranslation()){autosnappedTranslation=IntPoint::Round(matrix2D.GetTranslation());MatrixsnappedMatrix=Matrix::Translation(snappedTranslation.x,snappedTranslation.y);Matrix4x4result=Matrix4x4::From2D(snappedMatrix);if(aResidualTransform){// set aResidualTransform so that aResidual * snappedMatrix == matrix2D.// (I.e., appying snappedMatrix after aResidualTransform gives the// ideal transform.)*aResidualTransform=Matrix::Translation(matrix2D._31-snappedTranslation.x,matrix2D._32-snappedTranslation.y);}returnresult;}returnSnapTransformTranslation3D(aTransform,aResidualTransform);}Matrix4x4Layer::SnapTransformTranslation3D(constMatrix4x4&aTransform,Matrix*aResidualTransform){if(aTransform.IsSingular()||aTransform.HasPerspectiveComponent()||aTransform.HasNonTranslation()||!aTransform.HasNonIntegerTranslation()){// For a singular transform, there is no reversed matrix, so we// don't snap it.// For a perspective transform, the content is transformed in// non-linear, so we don't snap it too.returnaTransform;}// Snap for 3D TransformsPoint3DtransformedOrigin=aTransform.TransformPoint(Point3D());// Compute the transformed snap by rounding the values of// transformed origin.autotransformedSnapXY=IntPoint::Round(transformedOrigin.x,transformedOrigin.y);Matrix4x4inverse=aTransform;inverse.Invert();// see Matrix4x4::ProjectPoint()FloattransformedSnapZ=inverse._33==0?0:(-(transformedSnapXY.x*inverse._13+transformedSnapXY.y*inverse._23+inverse._43)/inverse._33);Point3DtransformedSnap=Point3D(transformedSnapXY.x,transformedSnapXY.y,transformedSnapZ);if(transformedOrigin==transformedSnap){returnaTransform;}// Compute the snap from the transformed snap.Point3Dsnap=inverse.TransformPoint(transformedSnap);if(snap.z>0.001||snap.z<-0.001){// Allow some level of accumulated computation error.MOZ_ASSERT(inverse._33==0.0);returnaTransform;}// The difference between the origin and snap is the residual transform.if(aResidualTransform){// The residual transform is to translate the snap to the origin// of the content buffer.*aResidualTransform=Matrix::Translation(-snap.x,-snap.y);}// Translate transformed origin to transformed snap since the// residual transform would trnslate the snap to the origin.Point3DtransformedShift=transformedSnap-transformedOrigin;Matrix4x4result=aTransform;result.PostTranslate(transformedShift.x,transformedShift.y,transformedShift.z);// For non-2d transform, residual translation could be more than// 0.5 pixels for every axis.returnresult;}Matrix4x4Layer::SnapTransform(constMatrix4x4&aTransform,constgfxRect&aSnapRect,Matrix*aResidualTransform){if(aResidualTransform){*aResidualTransform=Matrix();}Matrixmatrix2D;Matrix4x4result;if(mManager->IsSnappingEffectiveTransforms()&&aTransform.Is2D(&matrix2D)&&gfxSize(1.0,1.0)<=aSnapRect.Size()&&matrix2D.PreservesAxisAlignedRectangles()){autotransformedTopLeft=IntPoint::Round(matrix2D.TransformPoint(ToPoint(aSnapRect.TopLeft())));autotransformedTopRight=IntPoint::Round(matrix2D.TransformPoint(ToPoint(aSnapRect.TopRight())));autotransformedBottomRight=IntPoint::Round(matrix2D.TransformPoint(ToPoint(aSnapRect.BottomRight())));MatrixsnappedMatrix=gfxUtils::TransformRectToRect(aSnapRect,transformedTopLeft,transformedTopRight,transformedBottomRight);result=Matrix4x4::From2D(snappedMatrix);if(aResidualTransform&&!snappedMatrix.IsSingular()){// set aResidualTransform so that aResidual * snappedMatrix == matrix2D.// (i.e., appying snappedMatrix after aResidualTransform gives the// ideal transform.MatrixsnappedMatrixInverse=snappedMatrix;snappedMatrixInverse.Invert();*aResidualTransform=matrix2D*snappedMatrixInverse;}}else{result=aTransform;}returnresult;}staticboolAncestorLayerMayChangeTransform(Layer*aLayer){for(Layer*l=aLayer;l;l=l->GetParent()){if(l->GetContentFlags()&Layer::CONTENT_MAY_CHANGE_TRANSFORM){returntrue;}}returnfalse;}boolLayer::MayResample(){Matrixtransform2d;return!GetEffectiveTransform().Is2D(&transform2d)||ThebesMatrix(transform2d).HasNonIntegerTranslation()||AncestorLayerMayChangeTransform(this);}RenderTargetIntRectLayer::CalculateScissorRect(constRenderTargetIntRect&aCurrentScissorRect){ContainerLayer*container=GetParent();ContainerLayer*containerChild=nullptr;NS_ASSERTION(GetParent(),"This can't be called on the root!");// Find the layer creating the 3D context.while(container->Extend3DContext()&&!container->UseIntermediateSurface()){containerChild=container;container=container->GetParent();MOZ_ASSERT(container);}// Find the nearest layer with a clip, or this layer.// ContainerState::SetupScrollingMetadata() may install a clip on// the layer.Layer*clipLayer=containerChild&&containerChild->GetLocalClipRect()?containerChild:this;// Establish initial clip rect: it's either the one passed in, or// if the parent has an intermediate surface, it's the extents of that surface.RenderTargetIntRectcurrentClip;if(container->UseIntermediateSurface()){currentClip.SizeTo(container->GetIntermediateSurfaceRect().Size());}else{currentClip=aCurrentScissorRect;}if(!clipLayer->GetLocalClipRect()){returncurrentClip;}if(GetLocalVisibleRegion().IsEmpty()){// When our visible region is empty, our parent may not have created the// intermediate surface that we would require for correct clipping; however,// this does not matter since we are invisible.// Make sure we still compute a clip rect if we want to draw checkboarding// for this layer, since we want to do this even if the layer is invisible.returnRenderTargetIntRect(currentClip.TopLeft(),RenderTargetIntSize(0,0));}constRenderTargetIntRectclipRect=ViewAs<RenderTargetPixel>(*clipLayer->GetLocalClipRect(),PixelCastJustification::RenderTargetIsParentLayerForRoot);if(clipRect.IsEmpty()){// We might have a non-translation transform in the container so we can't// use the code path below.returnRenderTargetIntRect(currentClip.TopLeft(),RenderTargetIntSize(0,0));}RenderTargetIntRectscissor=clipRect;if(!container->UseIntermediateSurface()){gfx::Matrixmatrix;DebugOnly<bool>is2D=container->GetEffectiveTransform().Is2D(&matrix);// See DefaultComputeEffectiveTransforms belowNS_ASSERTION(is2D&&matrix.PreservesAxisAlignedRectangles(),"Non preserves axis aligned transform with clipped child should have forced intermediate surface");gfx::Rectr(scissor.x,scissor.y,scissor.width,scissor.height);gfxRecttrScissor=gfx::ThebesRect(matrix.TransformBounds(r));trScissor.Round();IntRecttmp;if(!gfxUtils::GfxRectToIntRect(trScissor,&tmp)){returnRenderTargetIntRect(currentClip.TopLeft(),RenderTargetIntSize(0,0));}scissor=ViewAs<RenderTargetPixel>(tmp);// Find the nearest ancestor with an intermediate surfacedo{container=container->GetParent();}while(container&&!container->UseIntermediateSurface());}if(container){scissor.MoveBy(-container->GetIntermediateSurfaceRect().TopLeft());}returncurrentClip.Intersect(scissor);}Maybe<ParentLayerIntRect>Layer::GetScrolledClipRect()const{constMaybe<LayerClip>clip=mSimpleAttrs.ScrolledClip();returnclip?Some(clip->GetClipRect()):Nothing();}constScrollMetadata&Layer::GetScrollMetadata(uint32_taIndex)const{MOZ_ASSERT(aIndex<GetScrollMetadataCount());returnmScrollMetadata[aIndex];}constFrameMetrics&Layer::GetFrameMetrics(uint32_taIndex)const{returnGetScrollMetadata(aIndex).GetMetrics();}boolLayer::HasScrollableFrameMetrics()const{for(uint32_ti=0;i<GetScrollMetadataCount();i++){if(GetFrameMetrics(i).IsScrollable()){returntrue;}}returnfalse;}boolLayer::IsScrollInfoLayer()const{// A scrollable container layer with no childrenreturnAsContainerLayer()&&HasScrollableFrameMetrics()&&!GetFirstChild();}Matrix4x4Layer::GetTransform()const{Matrix4x4transform=mSimpleAttrs.Transform();transform.PostScale(GetPostXScale(),GetPostYScale(),1.0f);if(constContainerLayer*c=AsContainerLayer()){transform.PreScale(c->GetPreXScale(),c->GetPreYScale(),1.0f);}returntransform;}constCSSTransformMatrixLayer::GetTransformTyped()const{returnViewAs<CSSTransformMatrix>(GetTransform());}Matrix4x4Layer::GetLocalTransform(){if(HostLayer*shadow=AsHostLayer()){returnshadow->GetShadowTransform();}returnGetTransform();}constLayerToParentLayerMatrix4x4Layer::GetLocalTransformTyped(){returnViewAs<LayerToParentLayerMatrix4x4>(GetLocalTransform());}boolLayer::HasOpacityAnimation()const{for(uint32_ti=0;i<mAnimations.Length();i++){if(mAnimations[i].property()==eCSSProperty_opacity){returntrue;}}returnfalse;}boolLayer::HasTransformAnimation()const{for(uint32_ti=0;i<mAnimations.Length();i++){if(mAnimations[i].property()==eCSSProperty_transform){returntrue;}}returnfalse;}voidLayer::ApplyPendingUpdatesForThisTransaction(){if(mPendingTransform&&*mPendingTransform!=mSimpleAttrs.Transform()){MOZ_LAYERS_LOG_IF_SHADOWABLE(this,("Layer::Mutated(%p) PendingUpdatesForThisTransaction",this));mSimpleAttrs.SetTransform(*mPendingTransform);MutatedSimple();}mPendingTransform=nullptr;if(mPendingAnimations){MOZ_LAYERS_LOG_IF_SHADOWABLE(this,("Layer::Mutated(%p) PendingUpdatesForThisTransaction",this));mPendingAnimations->SwapElements(mAnimations);mPendingAnimations=nullptr;Mutated();}for(size_ti=0;i<mScrollMetadata.Length();i++){FrameMetrics&fm=mScrollMetadata[i].GetMetrics();Maybe<ScrollUpdateInfo>update=Manager()->GetPendingScrollInfoUpdate(fm.GetScrollId());if(update){fm.UpdatePendingScrollInfo(update.value());Mutated();}}}floatLayer::GetLocalOpacity(){floatopacity=mSimpleAttrs.Opacity();if(HostLayer*shadow=AsHostLayer())opacity=shadow->GetShadowOpacity();returnstd::min(std::max(opacity,0.0f),1.0f);}floatLayer::GetEffectiveOpacity(){floatopacity=GetLocalOpacity();for(ContainerLayer*c=GetParent();c&&!c->UseIntermediateSurface();c=c->GetParent()){opacity*=c->GetLocalOpacity();}returnopacity;}CompositionOpLayer::GetEffectiveMixBlendMode(){if(mSimpleAttrs.MixBlendMode()!=CompositionOp::OP_OVER)returnmSimpleAttrs.MixBlendMode();for(ContainerLayer*c=GetParent();c&&!c->UseIntermediateSurface();c=c->GetParent()){if(c->mSimpleAttrs.MixBlendMode()!=CompositionOp::OP_OVER)returnc->mSimpleAttrs.MixBlendMode();}returnmSimpleAttrs.MixBlendMode();}voidLayer::ComputeEffectiveTransformForMaskLayers(constgfx::Matrix4x4&aTransformToSurface){if(GetMaskLayer()){ComputeEffectiveTransformForMaskLayer(GetMaskLayer(),aTransformToSurface);}for(size_ti=0;i<GetAncestorMaskLayerCount();i++){Layer*maskLayer=GetAncestorMaskLayerAt(i);ComputeEffectiveTransformForMaskLayer(maskLayer,aTransformToSurface);}}/* static */voidLayer::ComputeEffectiveTransformForMaskLayer(Layer*aMaskLayer,constgfx::Matrix4x4&aTransformToSurface){aMaskLayer->mEffectiveTransform=aTransformToSurface;#ifdef DEBUGboolmaskIs2D=aMaskLayer->GetTransform().CanDraw2D();NS_ASSERTION(maskIs2D,"How did we end up with a 3D transform here?!");#endif// The mask layer can have an async transform applied to it in some// situations, so be sure to use its GetLocalTransform() rather than// its GetTransform().aMaskLayer->mEffectiveTransform=aMaskLayer->GetLocalTransform()*aMaskLayer->mEffectiveTransform;}RenderTargetRectLayer::TransformRectToRenderTarget(constLayerIntRect&aRect){LayerRectrect(aRect);RenderTargetRectquad=RenderTargetRect::FromUnknownRect(GetEffectiveTransform().TransformBounds(rect.ToUnknownRect()));returnquad;}boolLayer::GetVisibleRegionRelativeToRootLayer(nsIntRegion&aResult,IntPoint*aLayerOffset){MOZ_ASSERT(aLayerOffset,"invalid offset pointer");if(!GetParent()){returnfalse;}IntPointoffset;aResult=GetLocalVisibleRegion().ToUnknownRegion();for(Layer*layer=this;layer;layer=layer->GetParent()){gfx::Matrixmatrix;if(!layer->GetLocalTransform().Is2D(&matrix)||!matrix.IsTranslation()){returnfalse;}// The offset of |layer| to its parent.autocurrentLayerOffset=IntPoint::Round(matrix.GetTranslation());// Translate the accumulated visible region of |this| by the offset of// |layer|.aResult.MoveBy(currentLayerOffset.x,currentLayerOffset.y);// If the parent layer clips its lower layers, clip the visible region// we're accumulating.if(layer->GetLocalClipRect()){aResult.AndWith(layer->GetLocalClipRect()->ToUnknownRect());}// Now we need to walk across the list of siblings for this parent layer,// checking to see if any of these layer trees obscure |this|. If so,// remove these areas from the visible region as well. This will pick up// chrome overlays like a tab modal prompt.Layer*sibling;for(sibling=layer->GetNextSibling();sibling;sibling=sibling->GetNextSibling()){gfx::MatrixsiblingMatrix;if(!sibling->GetLocalTransform().Is2D(&siblingMatrix)||!siblingMatrix.IsTranslation()){continue;}// Retreive the translation from sibling to |layer|. The accumulated// visible region is currently oriented with |layer|.autosiblingOffset=IntPoint::Round(siblingMatrix.GetTranslation());nsIntRegionsiblingVisibleRegion(sibling->GetLocalVisibleRegion().ToUnknownRegion());// Translate the siblings region to |layer|'s origin.siblingVisibleRegion.MoveBy(-siblingOffset.x,-siblingOffset.y);// Apply the sibling's clip.// Layer clip rects are not affected by the layer's transform.Maybe<ParentLayerIntRect>clipRect=sibling->GetLocalClipRect();if(clipRect){siblingVisibleRegion.AndWith(clipRect->ToUnknownRect());}// Subtract the sibling visible region from the visible region of |this|.aResult.SubOut(siblingVisibleRegion);}// Keep track of the total offset for aLayerOffset. We use this in plugin// positioning code.offset+=currentLayerOffset;}*aLayerOffset=IntPoint(offset.x,offset.y);returntrue;}Maybe<ParentLayerIntRect>Layer::GetCombinedClipRect()const{Maybe<ParentLayerIntRect>clip=GetClipRect();clip=IntersectMaybeRects(clip,GetScrolledClipRect());for(size_ti=0;i<mScrollMetadata.Length();i++){clip=IntersectMaybeRects(clip,mScrollMetadata[i].GetClipRect());}returnclip;}ContainerLayer::ContainerLayer(LayerManager*aManager,void*aImplData):Layer(aManager,aImplData),mFirstChild(nullptr),mLastChild(nullptr),mPreXScale(1.0f),mPreYScale(1.0f),mInheritedXScale(1.0f),mInheritedYScale(1.0f),mPresShellResolution(1.0f),mScaleToResolution(false),mUseIntermediateSurface(false),mSupportsComponentAlphaChildren(false),mMayHaveReadbackChild(false),mChildrenChanged(false),mEventRegionsOverride(EventRegionsOverride::NoOverride){}ContainerLayer::~ContainerLayer(){}boolContainerLayer::InsertAfter(Layer*aChild,Layer*aAfter){if(aChild->Manager()!=Manager()){NS_ERROR("Child has wrong manager");returnfalse;}if(aChild->GetParent()){NS_ERROR("aChild already in the tree");returnfalse;}if(aChild->GetNextSibling()||aChild->GetPrevSibling()){NS_ERROR("aChild already has siblings?");returnfalse;}if(aAfter&&(aAfter->Manager()!=Manager()||aAfter->GetParent()!=this)){NS_ERROR("aAfter is not our child");returnfalse;}aChild->SetParent(this);if(aAfter==mLastChild){mLastChild=aChild;}if(!aAfter){aChild->SetNextSibling(mFirstChild);if(mFirstChild){mFirstChild->SetPrevSibling(aChild);}mFirstChild=aChild;NS_ADDREF(aChild);DidInsertChild(aChild);returntrue;}Layer*next=aAfter->GetNextSibling();aChild->SetNextSibling(next);aChild->SetPrevSibling(aAfter);if(next){next->SetPrevSibling(aChild);}aAfter->SetNextSibling(aChild);NS_ADDREF(aChild);DidInsertChild(aChild);returntrue;}voidContainerLayer::RemoveAllChildren(){// Optimizes "while (mFirstChild) ContainerLayer::RemoveChild(mFirstChild);"Layer*current=mFirstChild;// This is inlining DidRemoveChild() on each layer; we can skip the calls// to NotifyPaintedLayerRemoved as it gets taken care of when as we call// NotifyRemoved prior to removing any layers.while(current){Layer*next=current->GetNextSibling();if(current->GetType()==TYPE_READBACK){static_cast<ReadbackLayer*>(current)->NotifyRemoved();}current=next;}current=mFirstChild;mFirstChild=nullptr;while(current){MOZ_ASSERT(!current->GetPrevSibling());Layer*next=current->GetNextSibling();current->SetParent(nullptr);current->SetNextSibling(nullptr);if(next){next->SetPrevSibling(nullptr);}NS_RELEASE(current);current=next;}}// Note that ContainerLayer::RemoveAllChildren is an optimized// version of this code; if you make changes to ContainerLayer::RemoveChild// consider whether the matching changes need to be made to// ContainerLayer::RemoveAllChildrenboolContainerLayer::RemoveChild(Layer*aChild){if(aChild->Manager()!=Manager()){NS_ERROR("Child has wrong manager");returnfalse;}if(aChild->GetParent()!=this){NS_ERROR("aChild not our child");returnfalse;}Layer*prev=aChild->GetPrevSibling();Layer*next=aChild->GetNextSibling();if(prev){prev->SetNextSibling(next);}else{this->mFirstChild=next;}if(next){next->SetPrevSibling(prev);}else{this->mLastChild=prev;}aChild->SetNextSibling(nullptr);aChild->SetPrevSibling(nullptr);aChild->SetParent(nullptr);this->DidRemoveChild(aChild);NS_RELEASE(aChild);returntrue;}boolContainerLayer::RepositionChild(Layer*aChild,Layer*aAfter){if(aChild->Manager()!=Manager()){NS_ERROR("Child has wrong manager");returnfalse;}if(aChild->GetParent()!=this){NS_ERROR("aChild not our child");returnfalse;}if(aAfter&&(aAfter->Manager()!=Manager()||aAfter->GetParent()!=this)){NS_ERROR("aAfter is not our child");returnfalse;}if(aChild==aAfter){NS_ERROR("aChild cannot be the same as aAfter");returnfalse;}Layer*prev=aChild->GetPrevSibling();Layer*next=aChild->GetNextSibling();if(prev==aAfter){// aChild is already in the correct position, nothing to do.returntrue;}if(prev){prev->SetNextSibling(next);}else{mFirstChild=next;}if(next){next->SetPrevSibling(prev);}else{mLastChild=prev;}if(!aAfter){aChild->SetPrevSibling(nullptr);aChild->SetNextSibling(mFirstChild);if(mFirstChild){mFirstChild->SetPrevSibling(aChild);}mFirstChild=aChild;returntrue;}Layer*afterNext=aAfter->GetNextSibling();if(afterNext){afterNext->SetPrevSibling(aChild);}else{mLastChild=aChild;}aAfter->SetNextSibling(aChild);aChild->SetPrevSibling(aAfter);aChild->SetNextSibling(afterNext);returntrue;}voidContainerLayer::FillSpecificAttributes(SpecificLayerAttributes&aAttrs){aAttrs=ContainerLayerAttributes(mPreXScale,mPreYScale,mInheritedXScale,mInheritedYScale,mPresShellResolution,mScaleToResolution,mEventRegionsOverride);}boolContainerLayer::Creates3DContextWithExtendingChildren(){if(Extend3DContext()){returnfalse;}for(Layer*child=GetFirstChild();child;child=child->GetNextSibling()){if(child->Extend3DContext()){returntrue;}}returnfalse;}boolContainerLayer::HasMultipleChildren(){uint32_tcount=0;for(Layer*child=GetFirstChild();child;child=child->GetNextSibling()){constMaybe<ParentLayerIntRect>&clipRect=child->GetLocalClipRect();if(clipRect&&clipRect->IsEmpty())continue;if(child->GetLocalVisibleRegion().IsEmpty())continue;++count;if(count>1)returntrue;}returnfalse;}/** * Collect all leaf descendants of the current 3D context. */voidContainerLayer::Collect3DContextLeaves(nsTArray<Layer*>&aToSort){ForEachNode<ForwardIterator>((Layer*)this,[this,&aToSort](Layer*layer){ContainerLayer*container=layer->AsContainerLayer();if(layer==this||(container&&container->Extend3DContext()&&!container->UseIntermediateSurface())){returnTraversalFlag::Continue;}aToSort.AppendElement(layer);returnTraversalFlag::Skip;});}staticnsTArray<LayerPolygon>SortLayersWithBSPTree(nsTArray<Layer*>&aArray){std::list<LayerPolygon>inputLayers;// Build a list of polygons to be sorted.for(Layer*layer:aArray){// Ignore invisible layers.if(!layer->IsVisible()){continue;}constgfx::IntRect&bounds=layer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();constgfx::Matrix4x4&transform=layer->GetEffectiveTransform();if(transform.IsSingular()){// Transform cannot be inverted.continue;}gfx::Polygonpolygon=gfx::Polygon::FromRect(gfx::Rect(bounds));// Transform the polygon to screen space.polygon.TransformToScreenSpace(transform);if(polygon.GetPoints().Length()>=3){inputLayers.push_back(LayerPolygon(layer,Move(polygon)));}}if(inputLayers.empty()){returnnsTArray<LayerPolygon>();}// Build a BSP tree from the list of polygons.BSPTreetree(inputLayers);nsTArray<LayerPolygon>orderedLayers(tree.GetDrawOrder());// Transform the polygons back to layer space.for(LayerPolygon&layerPolygon:orderedLayers){gfx::Matrix4x4inverse=layerPolygon.layer->GetEffectiveTransform().Inverse();MOZ_ASSERT(layerPolygon.geometry);layerPolygon.geometry->TransformToLayerSpace(inverse);}returnorderedLayers;}staticnsTArray<LayerPolygon>StripLayerGeometry(constnsTArray<LayerPolygon>&aLayers){nsTArray<LayerPolygon>layers;std::set<Layer*>uniqueLayers;for(constLayerPolygon&layerPolygon:aLayers){autoresult=uniqueLayers.insert(layerPolygon.layer);if(result.second){// Layer was added to the set.layers.AppendElement(LayerPolygon(layerPolygon.layer));}}returnlayers;}nsTArray<LayerPolygon>ContainerLayer::SortChildrenBy3DZOrder(SortModeaSortMode){AutoTArray<Layer*,10>toSort;nsTArray<LayerPolygon>drawOrder;for(Layer*layer=GetFirstChild();layer;layer=layer->GetNextSibling()){ContainerLayer*container=layer->AsContainerLayer();if(container&&container->Extend3DContext()&&!container->UseIntermediateSurface()){// Collect 3D layers in toSort array.container->Collect3DContextLeaves(toSort);// Sort the 3D layers.if(toSort.Length()>0){nsTArray<LayerPolygon>sorted=SortLayersWithBSPTree(toSort);drawOrder.AppendElements(Move(sorted));toSort.ClearAndRetainStorage();}continue;}drawOrder.AppendElement(LayerPolygon(layer));}if(aSortMode==SortMode::WITHOUT_GEOMETRY){// Compositor does not support arbitrary layers, strip the layer geometry// and duplicate layers.returnStripLayerGeometry(drawOrder);}returndrawOrder;}boolContainerLayer::AnyAncestorOrThisIs3DContextLeaf(){Layer*parent=this;while(parent!=nullptr){if(parent->Is3DContextLeaf()){returntrue;}parent=parent->GetParent();}returnfalse;}voidContainerLayer::DefaultComputeEffectiveTransforms(constMatrix4x4&aTransformToSurface){Matrixresidual;Matrix4x4idealTransform=GetLocalTransform()*aTransformToSurface;// Keep 3D transforms for leaves to keep z-order sorting correct.if(!Extend3DContext()&&!Is3DContextLeaf()){idealTransform.ProjectTo2D();}booluseIntermediateSurface;if(HasMaskLayers()||GetForceIsolatedGroup()){useIntermediateSurface=true;#ifdef MOZ_DUMP_PAINTING}elseif(gfxEnv::DumpPaintIntermediate()&&!Extend3DContext()){useIntermediateSurface=true;#endif}else{/* Don't use an intermediate surface for opacity when it's within a 3d * context, since we'd rather keep the 3d effects. This matches the * WebKit/blink behaviour, but is changing in the latest spec. */floatopacity=GetEffectiveOpacity();CompositionOpblendMode=GetEffectiveMixBlendMode();if((HasMultipleChildren()||Creates3DContextWithExtendingChildren())&&((opacity!=1.0f&&!Extend3DContext())||(blendMode!=CompositionOp::OP_OVER))){useIntermediateSurface=true;}elseif((!idealTransform.Is2D()||AnyAncestorOrThisIs3DContextLeaf())&&Creates3DContextWithExtendingChildren()){useIntermediateSurface=true;}elseif(blendMode!=CompositionOp::OP_OVER&&Manager()->BlendingRequiresIntermediateSurface()){useIntermediateSurface=true;}else{useIntermediateSurface=false;gfx::MatrixcontTransform;boolcheckClipRect=false;boolcheckMaskLayers=false;if(!idealTransform.Is2D(&contTransform)){// In 3D case, always check if we should use IntermediateSurface.checkClipRect=true;checkMaskLayers=true;}else{#ifdef MOZ_GFX_OPTIMIZE_MOBILEif(!contTransform.PreservesAxisAlignedRectangles()){#elseif(gfx::ThebesMatrix(contTransform).HasNonIntegerTranslation()){#endifcheckClipRect=true;}/* In 2D case, only translation and/or positive scaling can be done w/o using IntermediateSurface. * Otherwise, when rotation or flip happen, we should check whether to use IntermediateSurface. */if(contTransform.HasNonAxisAlignedTransform()||contTransform.HasNegativeScaling()){checkMaskLayers=true;}}if(checkClipRect||checkMaskLayers){for(Layer*child=GetFirstChild();child;child=child->GetNextSibling()){constMaybe<ParentLayerIntRect>&clipRect=child->GetLocalClipRect();/* We can't (easily) forward our transform to children with a non-empty clip * rect since it would need to be adjusted for the transform. See * the calculations performed by CalculateScissorRect above. * Nor for a child with a mask layer. */if(checkClipRect&&(clipRect&&!clipRect->IsEmpty()&&!child->GetLocalVisibleRegion().IsEmpty())){useIntermediateSurface=true;break;}if(checkMaskLayers&&child->HasMaskLayers()){useIntermediateSurface=true;break;}}}}}NS_ASSERTION(!Extend3DContext()||!useIntermediateSurface,"Can't have an intermediate surface with preserve-3d!");if(useIntermediateSurface){mEffectiveTransform=SnapTransformTranslation(idealTransform,&residual);}else{mEffectiveTransform=idealTransform;}// For layers extending 3d context, its ideal transform should be// applied on children.if(!Extend3DContext()){// Without this projection, non-container children would get a 3D// transform while 2D is expected.idealTransform.ProjectTo2D();}mUseIntermediateSurface=useIntermediateSurface&&!GetLocalVisibleRegion().IsEmpty();if(useIntermediateSurface){ComputeEffectiveTransformsForChildren(Matrix4x4::From2D(residual));}else{ComputeEffectiveTransformsForChildren(idealTransform);}ComputeEffectiveTransformForMaskLayers(aTransformToSurface);}voidContainerLayer::DefaultComputeSupportsComponentAlphaChildren(bool*aNeedsSurfaceCopy){if(!(GetContentFlags()&Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT)||!Manager()->AreComponentAlphaLayersEnabled()){mSupportsComponentAlphaChildren=false;if(aNeedsSurfaceCopy){*aNeedsSurfaceCopy=false;}return;}mSupportsComponentAlphaChildren=false;boolneedsSurfaceCopy=false;CompositionOpblendMode=GetEffectiveMixBlendMode();if(UseIntermediateSurface()){if(GetLocalVisibleRegion().GetNumRects()==1&&(GetContentFlags()&Layer::CONTENT_OPAQUE)){mSupportsComponentAlphaChildren=true;}else{gfx::Matrixtransform;if(HasOpaqueAncestorLayer(this)&&GetEffectiveTransform().Is2D(&transform)&&!gfx::ThebesMatrix(transform).HasNonIntegerTranslation()&&blendMode==gfx::CompositionOp::OP_OVER&&Manager()->SupportsBackdropCopyForComponentAlpha()){mSupportsComponentAlphaChildren=true;needsSurfaceCopy=true;}}}elseif(blendMode==gfx::CompositionOp::OP_OVER){mSupportsComponentAlphaChildren=(GetContentFlags()&Layer::CONTENT_OPAQUE)||(GetParent()&&GetParent()->SupportsComponentAlphaChildren());}if(aNeedsSurfaceCopy){*aNeedsSurfaceCopy=mSupportsComponentAlphaChildren&&needsSurfaceCopy;}}voidContainerLayer::ComputeEffectiveTransformsForChildren(constMatrix4x4&aTransformToSurface){for(Layer*l=mFirstChild;l;l=l->GetNextSibling()){l->ComputeEffectiveTransforms(aTransformToSurface);}}/* static */boolContainerLayer::HasOpaqueAncestorLayer(Layer*aLayer){for(Layer*l=aLayer->GetParent();l;l=l->GetParent()){if(l->GetContentFlags()&Layer::CONTENT_OPAQUE)returntrue;}returnfalse;}// Note that ContainerLayer::RemoveAllChildren contains an optimized// version of this code; if you make changes to ContainerLayer::DidRemoveChild// consider whether the matching changes need to be made to// ContainerLayer::RemoveAllChildrenvoidContainerLayer::DidRemoveChild(Layer*aLayer){PaintedLayer*tl=aLayer->AsPaintedLayer();if(tl&&tl->UsedForReadback()){for(Layer*l=mFirstChild;l;l=l->GetNextSibling()){if(l->GetType()==TYPE_READBACK){static_cast<ReadbackLayer*>(l)->NotifyPaintedLayerRemoved(tl);}}}if(aLayer->GetType()==TYPE_READBACK){static_cast<ReadbackLayer*>(aLayer)->NotifyRemoved();}}voidContainerLayer::DidInsertChild(Layer*aLayer){if(aLayer->GetType()==TYPE_READBACK){mMayHaveReadbackChild=true;}}voidRefLayer::FillSpecificAttributes(SpecificLayerAttributes&aAttrs){aAttrs=RefLayerAttributes(GetReferentId(),mEventRegionsOverride);}/** * StartFrameTimeRecording, together with StopFrameTimeRecording * enable recording of frame intervals. * * To allow concurrent consumers, a cyclic array is used which serves all * consumers, practically stateless with regard to consumers. * * To save resources, the buffer is allocated on first call to StartFrameTimeRecording * and recording is paused if no consumer which called StartFrameTimeRecording is able * to get valid results (because the cyclic buffer was overwritten since that call). * * To determine availability of the data upon StopFrameTimeRecording: * - mRecording.mNextIndex increases on each RecordFrame, and never resets. * - Cyclic buffer position is realized as mNextIndex % bufferSize. * - StartFrameTimeRecording returns mNextIndex. When StopFrameTimeRecording is called, * the required start index is passed as an arg, and we're able to calculate the required * length. If this length is bigger than bufferSize, it means data was overwritten. * otherwise, we can return the entire sequence. * - To determine if we need to pause, mLatestStartIndex is updated to mNextIndex * on each call to StartFrameTimeRecording. If this index gets overwritten, * it means that all earlier start indices obtained via StartFrameTimeRecording * were also overwritten, hence, no point in recording, so pause. * - mCurrentRunStartIndex indicates the oldest index of the recording after which * the recording was not paused. If StopFrameTimeRecording is invoked with a start index * older than this, it means that some frames were not recorded, so data is invalid. */uint32_tLayerManager::StartFrameTimeRecording(int32_taBufferSize){if(mRecording.mIsPaused){mRecording.mIsPaused=false;if(!mRecording.mIntervals.Length()){// Initialize recording buffersmRecording.mIntervals.SetLength(aBufferSize);}// After being paused, recent values got invalid. Update them to now.mRecording.mLastFrameTime=TimeStamp::Now();// Any recording which started before this is invalid, since we were paused.mRecording.mCurrentRunStartIndex=mRecording.mNextIndex;}// If we'll overwrite this index, there are no more consumers with aStartIndex// for which we're able to provide the full recording, so no point in keep recording.mRecording.mLatestStartIndex=mRecording.mNextIndex;returnmRecording.mNextIndex;}voidLayerManager::RecordFrame(){if(!mRecording.mIsPaused){TimeStampnow=TimeStamp::Now();uint32_ti=mRecording.mNextIndex%mRecording.mIntervals.Length();mRecording.mIntervals[i]=static_cast<float>((now-mRecording.mLastFrameTime).ToMilliseconds());mRecording.mNextIndex++;mRecording.mLastFrameTime=now;if(mRecording.mNextIndex>(mRecording.mLatestStartIndex+mRecording.mIntervals.Length())){// We've just overwritten the most recent recording start -> pause.mRecording.mIsPaused=true;}}}voidLayerManager::StopFrameTimeRecording(uint32_taStartIndex,nsTArray<float>&aFrameIntervals){uint32_tbufferSize=mRecording.mIntervals.Length();uint32_tlength=mRecording.mNextIndex-aStartIndex;if(mRecording.mIsPaused||length>bufferSize||aStartIndex<mRecording.mCurrentRunStartIndex){// aStartIndex is too old. Also if aStartIndex was issued before mRecordingNextIndex overflowed (uint32_t)// and stopped after the overflow (would happen once every 828 days of constant 60fps).length=0;}if(!length){aFrameIntervals.Clear();return;// empty recording, return empty arrays.}// Set length in advance to avoid possibly repeated reallocationsaFrameIntervals.SetLength(length);uint32_tcyclicPos=aStartIndex%bufferSize;for(uint32_ti=0;i<length;i++,cyclicPos++){if(cyclicPos==bufferSize){cyclicPos=0;}aFrameIntervals[i]=mRecording.mIntervals[cyclicPos];}}staticvoidPrintInfo(std::stringstream&aStream,HostLayer*aLayerComposite);#ifdef MOZ_DUMP_PAINTINGtemplate<typenameT>voidWriteSnapshotToDumpFile_internal(T*aObj,DataSourceSurface*aSurf){nsCStringstring(aObj->Name());string.Append('-');string.AppendInt((uint64_t)aObj);if(gfxUtils::sDumpPaintFile!=stderr){fprintf_stderr(gfxUtils::sDumpPaintFile,R"(array["%s"]=")",string.BeginReading());}gfxUtils::DumpAsDataURI(aSurf,gfxUtils::sDumpPaintFile);if(gfxUtils::sDumpPaintFile!=stderr){fprintf_stderr(gfxUtils::sDumpPaintFile,R"(";)");}}voidWriteSnapshotToDumpFile(Layer*aLayer,DataSourceSurface*aSurf){WriteSnapshotToDumpFile_internal(aLayer,aSurf);}voidWriteSnapshotToDumpFile(LayerManager*aManager,DataSourceSurface*aSurf){WriteSnapshotToDumpFile_internal(aManager,aSurf);}voidWriteSnapshotToDumpFile(Compositor*aCompositor,DrawTarget*aTarget){RefPtr<SourceSurface>surf=aTarget->Snapshot();RefPtr<DataSourceSurface>dSurf=surf->GetDataSurface();WriteSnapshotToDumpFile_internal(aCompositor,dSurf);}#endifvoidLayer::Dump(std::stringstream&aStream,constchar*aPrefix,boolaDumpHtml,boolaSorted,constMaybe<gfx::Polygon>&aGeometry){#ifdef MOZ_DUMP_PAINTINGbooldumpCompositorTexture=gfxEnv::DumpCompositorTextures()&&AsHostLayer()&&AsHostLayer()->GetCompositableHost();booldumpClientTexture=gfxEnv::DumpPaint()&&AsShadowableLayer()&&AsShadowableLayer()->GetCompositableClient();nsCStringlayerId(Name());layerId.Append('-');layerId.AppendInt((uint64_t)this);#endifif(aDumpHtml){aStream<<nsPrintfCString(R"(<li><a id="%p" )",this).get();#ifdef MOZ_DUMP_PAINTINGif(dumpCompositorTexture||dumpClientTexture){aStream<<nsPrintfCString(R"lit(href="javascript:ViewImage('%s')")lit",layerId.BeginReading()).get();}#endifaStream<<">";}DumpSelf(aStream,aPrefix,aGeometry);#ifdef MOZ_DUMP_PAINTINGif(dumpCompositorTexture){AsHostLayer()->GetCompositableHost()->Dump(aStream,aPrefix,aDumpHtml);}elseif(dumpClientTexture){if(aDumpHtml){aStream<<nsPrintfCString(R"(<script>array["%s"]=")",layerId.BeginReading()).get();}AsShadowableLayer()->GetCompositableClient()->Dump(aStream,aPrefix,aDumpHtml,TextureDumpMode::DoNotCompress);if(aDumpHtml){aStream<<R"(";</script>)";}}#endifif(aDumpHtml){aStream<<"</a>";#ifdef MOZ_DUMP_PAINTINGif(dumpClientTexture){aStream<<nsPrintfCString("<br><img id=\"%s\">\n",layerId.BeginReading()).get();}#endif}if(Layer*mask=GetMaskLayer()){aStream<<nsPrintfCString("%s Mask layer:\n",aPrefix).get();nsAutoCStringpfx(aPrefix);pfx+=" ";mask->Dump(aStream,pfx.get(),aDumpHtml);}for(size_ti=0;i<GetAncestorMaskLayerCount();i++){aStream<<nsPrintfCString("%s Ancestor mask layer %d:\n",aPrefix,uint32_t(i)).get();nsAutoCStringpfx(aPrefix);pfx+=" ";GetAncestorMaskLayerAt(i)->Dump(aStream,pfx.get(),aDumpHtml);}#ifdef MOZ_DUMP_PAINTINGfor(size_ti=0;i<mExtraDumpInfo.Length();i++){constnsCString&str=mExtraDumpInfo[i];aStream<<aPrefix<<" Info:\n"<<str.get();}#endifif(ContainerLayer*container=AsContainerLayer()){nsTArray<LayerPolygon>children;if(aSorted){children=container->SortChildrenBy3DZOrder(ContainerLayer::SortMode::WITH_GEOMETRY);}else{for(Layer*l=container->GetFirstChild();l;l=l->GetNextSibling()){children.AppendElement(LayerPolygon(l));}}nsAutoCStringpfx(aPrefix);pfx+=" ";if(aDumpHtml){aStream<<"<ul>";}for(LayerPolygon&child:children){child.layer->Dump(aStream,pfx.get(),aDumpHtml,aSorted,child.geometry);}if(aDumpHtml){aStream<<"</ul>";}}if(aDumpHtml){aStream<<"</li>";}}staticvoidDumpGeometry(std::stringstream&aStream,constMaybe<gfx::Polygon>&aGeometry){aStream<<" [geometry=[";constnsTArray<gfx::Point4D>&points=aGeometry->GetPoints();for(size_ti=0;i<points.Length();++i){constgfx::IntPointpoint=TruncatedToInt(points[i].As2DPoint());constchar*sfx=(i!=points.Length()-1)?",":"";AppendToString(aStream,point,"",sfx);}aStream<<"]]";}voidLayer::DumpSelf(std::stringstream&aStream,constchar*aPrefix,constMaybe<gfx::Polygon>&aGeometry){PrintInfo(aStream,aPrefix);if(aGeometry){DumpGeometry(aStream,aGeometry);}aStream<<"\n";}voidLayer::Dump(layerscope::LayersPacket*aPacket,constvoid*aParent){DumpPacket(aPacket,aParent);if(Layer*kid=GetFirstChild()){kid->Dump(aPacket,this);}if(Layer*next=GetNextSibling()){next->Dump(aPacket,aParent);}}voidLayer::SetDisplayListLog(constchar*log){if(gfxUtils::DumpDisplayList()){mDisplayListLog=log;}}voidLayer::GetDisplayListLog(nsCString&log){log.SetLength(0);if(gfxUtils::DumpDisplayList()){// This function returns a plain text string which consists of two things// 1. DisplayList log.// 2. Memory address of this layer.// We know the target layer of each display item by information in #1.// Here is an example of a Text display item line log in #1// Text p=0xa9850c00 f=0x0xaa405b00(.....// f keeps the address of the target client layer of a display item.// For LayerScope, display-item-to-client-layer mapping is not enough since// LayerScope, which lives in the chrome process, knows only composite layers.// As so, we need display-item-to-client-layer-to-layer-composite// mapping. That's the reason we insert #2 into the loglog.AppendPrintf("0x%p\n%s",(void*)this,mDisplayListLog.get());}}voidLayer::Log(constchar*aPrefix){if(!IsLogEnabled())return;LogSelf(aPrefix);if(Layer*kid=GetFirstChild()){nsAutoCStringpfx(aPrefix);pfx+=" ";kid->Log(pfx.get());}if(Layer*next=GetNextSibling())next->Log(aPrefix);}voidLayer::LogSelf(constchar*aPrefix){if(!IsLogEnabled())return;std::stringstreamss;PrintInfo(ss,aPrefix);MOZ_LAYERS_LOG(("%s",ss.str().c_str()));if(mMaskLayer){nsAutoCStringpfx(aPrefix);pfx+=R"( \ MaskLayer )";mMaskLayer->LogSelf(pfx.get());}}voidLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){aStream<<aPrefix;aStream<<nsPrintfCString("%s%s (0x%p)",mManager->Name(),Name(),this).get();layers::PrintInfo(aStream,AsHostLayer());if(mClipRect){AppendToString(aStream,*mClipRect," [clip=","]");}if(mSimpleAttrs.ScrolledClip()){AppendToString(aStream,mSimpleAttrs.ScrolledClip()->GetClipRect()," [scrolled-clip=","]");if(constMaybe<size_t>&ix=mSimpleAttrs.ScrolledClip()->GetMaskLayerIndex()){AppendToString(aStream,ix.value()," [scrolled-mask=","]");}}if(1.0!=mSimpleAttrs.PostXScale()||1.0!=mSimpleAttrs.PostYScale()){aStream<<nsPrintfCString(" [postScale=%g, %g]",mSimpleAttrs.PostXScale(),mSimpleAttrs.PostYScale()).get();}if(!GetBaseTransform().IsIdentity()){AppendToString(aStream,GetBaseTransform()," [transform=","]");}if(!GetEffectiveTransform().IsIdentity()){AppendToString(aStream,GetEffectiveTransform()," [effective-transform=","]");}if(GetTransformIsPerspective()){aStream<<" [perspective]";}if(!mVisibleRegion.IsEmpty()){AppendToString(aStream,mVisibleRegion.ToUnknownRegion()," [visible=","]");}else{aStream<<" [not visible]";}if(!mEventRegions.IsEmpty()){AppendToString(aStream,mEventRegions," ","");}if(1.0!=GetOpacity()){aStream<<nsPrintfCString(" [opacity=%g]",GetOpacity()).get();}if(IsOpaque()){aStream<<" [opaqueContent]";}if(GetContentFlags()&CONTENT_COMPONENT_ALPHA){aStream<<" [componentAlpha]";}if(GetContentFlags()&CONTENT_BACKFACE_HIDDEN){aStream<<" [backfaceHidden]";}if(Extend3DContext()){aStream<<" [extend3DContext]";}if(Combines3DTransformWithAncestors()){aStream<<" [combines3DTransformWithAncestors]";}if(Is3DContextLeaf()){aStream<<" [is3DContextLeaf]";}if(IsScrollbarContainer()){aStream<<" [scrollbar]";}ScrollDirectionthumbDirection=GetScrollThumbData().mDirection;if(thumbDirection==ScrollDirection::VERTICAL){aStream<<nsPrintfCString(" [vscrollbar=%"PRIu64"]",GetScrollbarTargetContainerId()).get();}if(thumbDirection==ScrollDirection::HORIZONTAL){aStream<<nsPrintfCString(" [hscrollbar=%"PRIu64"]",GetScrollbarTargetContainerId()).get();}if(GetIsFixedPosition()){LayerPointanchor=GetFixedPositionAnchor();aStream<<nsPrintfCString(" [isFixedPosition scrollId=%"PRIu64" sides=0x%x anchor=%s]",GetFixedPositionScrollContainerId(),GetFixedPositionSides(),ToString(anchor).c_str()).get();}if(GetIsStickyPosition()){aStream<<nsPrintfCString(" [isStickyPosition scrollId=%"PRIu64" outer=(%.3f,%.3f)-(%.3f,%.3f) ""inner=(%.3f,%.3f)-(%.3f,%.3f)]",GetStickyScrollContainerId(),GetStickyScrollRangeOuter().x,GetStickyScrollRangeOuter().y,GetStickyScrollRangeOuter().XMost(),GetStickyScrollRangeOuter().YMost(),GetStickyScrollRangeInner().x,GetStickyScrollRangeInner().y,GetStickyScrollRangeInner().XMost(),GetStickyScrollRangeInner().YMost()).get();}if(mMaskLayer){aStream<<nsPrintfCString(" [mMaskLayer=%p]",mMaskLayer.get()).get();}for(uint32_ti=0;i<mScrollMetadata.Length();i++){if(!mScrollMetadata[i].IsDefault()){aStream<<nsPrintfCString(" [metrics%d=",i).get();AppendToString(aStream,mScrollMetadata[i],"","]");}}if(!mAnimations.IsEmpty()){aStream<<nsPrintfCString(" [%d animations with id=%"PRIu64" ]",(int)mAnimations.Length(),mCompositorAnimationsId).get();}}// The static helper function sets the transform matrix into the packetstaticvoidDumpTransform(layerscope::LayersPacket::Layer::Matrix*aLayerMatrix,constMatrix4x4&aMatrix){aLayerMatrix->set_is2d(aMatrix.Is2D());if(aMatrix.Is2D()){Matrixm=aMatrix.As2D();aLayerMatrix->set_isid(m.IsIdentity());if(!m.IsIdentity()){aLayerMatrix->add_m(m._11);aLayerMatrix->add_m(m._12);aLayerMatrix->add_m(m._21);aLayerMatrix->add_m(m._22);aLayerMatrix->add_m(m._31);aLayerMatrix->add_m(m._32);}}else{aLayerMatrix->add_m(aMatrix._11);aLayerMatrix->add_m(aMatrix._12);aLayerMatrix->add_m(aMatrix._13);aLayerMatrix->add_m(aMatrix._14);aLayerMatrix->add_m(aMatrix._21);aLayerMatrix->add_m(aMatrix._22);aLayerMatrix->add_m(aMatrix._23);aLayerMatrix->add_m(aMatrix._24);aLayerMatrix->add_m(aMatrix._31);aLayerMatrix->add_m(aMatrix._32);aLayerMatrix->add_m(aMatrix._33);aLayerMatrix->add_m(aMatrix._34);aLayerMatrix->add_m(aMatrix._41);aLayerMatrix->add_m(aMatrix._42);aLayerMatrix->add_m(aMatrix._43);aLayerMatrix->add_m(aMatrix._44);}}// The static helper function sets the IntRect into the packettemplate<typenameT,typenameSub,typenamePoint,typenameSizeT,typenameMarginT>staticvoidDumpRect(layerscope::LayersPacket::Layer::Rect*aLayerRect,constBaseRect<T,Sub,Point,SizeT,MarginT>&aRect){aLayerRect->set_x(aRect.x);aLayerRect->set_y(aRect.y);aLayerRect->set_w(aRect.width);aLayerRect->set_h(aRect.height);}// The static helper function sets the nsIntRegion into the packetstaticvoidDumpRegion(layerscope::LayersPacket::Layer::Region*aLayerRegion,constnsIntRegion&aRegion){for(autoiter=aRegion.RectIter();!iter.Done();iter.Next()){DumpRect(aLayerRegion->add_r(),iter.Get());}}voidLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){// Add a new layer (UnknownLayer)usingnamespacelayerscope;LayersPacket::Layer*layer=aPacket->add_layer();// Basic informationlayer->set_type(LayersPacket::Layer::UnknownLayer);layer->set_ptr(reinterpret_cast<uint64_t>(this));layer->set_parentptr(reinterpret_cast<uint64_t>(aParent));// Shadowif(HostLayer*lc=AsHostLayer()){LayersPacket::Layer::Shadow*s=layer->mutable_shadow();if(constMaybe<ParentLayerIntRect>&clipRect=lc->GetShadowClipRect()){DumpRect(s->mutable_clip(),*clipRect);}if(!lc->GetShadowBaseTransform().IsIdentity()){DumpTransform(s->mutable_transform(),lc->GetShadowBaseTransform());}if(!lc->GetShadowVisibleRegion().IsEmpty()){DumpRegion(s->mutable_vregion(),lc->GetShadowVisibleRegion().ToUnknownRegion());}}// Clipif(mClipRect){DumpRect(layer->mutable_clip(),*mClipRect);}// Transformif(!GetBaseTransform().IsIdentity()){DumpTransform(layer->mutable_transform(),GetBaseTransform());}// Visible regionif(!mVisibleRegion.ToUnknownRegion().IsEmpty()){DumpRegion(layer->mutable_vregion(),mVisibleRegion.ToUnknownRegion());}// EventRegionsif(!mEventRegions.IsEmpty()){constEventRegions&e=mEventRegions;if(!e.mHitRegion.IsEmpty()){DumpRegion(layer->mutable_hitregion(),e.mHitRegion);}if(!e.mDispatchToContentHitRegion.IsEmpty()){DumpRegion(layer->mutable_dispatchregion(),e.mDispatchToContentHitRegion);}if(!e.mNoActionRegion.IsEmpty()){DumpRegion(layer->mutable_noactionregion(),e.mNoActionRegion);}if(!e.mHorizontalPanRegion.IsEmpty()){DumpRegion(layer->mutable_hpanregion(),e.mHorizontalPanRegion);}if(!e.mVerticalPanRegion.IsEmpty()){DumpRegion(layer->mutable_vpanregion(),e.mVerticalPanRegion);}}// Opacitylayer->set_opacity(GetOpacity());// Content opaquelayer->set_copaque(static_cast<bool>(GetContentFlags()&CONTENT_OPAQUE));// Component alphalayer->set_calpha(static_cast<bool>(GetContentFlags()&CONTENT_COMPONENT_ALPHA));// Vertical or horizontal barScrollDirectionthumbDirection=GetScrollThumbData().mDirection;if(thumbDirection!=ScrollDirection::NONE){layer->set_direct(thumbDirection==ScrollDirection::VERTICAL?LayersPacket::Layer::VERTICAL:LayersPacket::Layer::HORIZONTAL);layer->set_barid(GetScrollbarTargetContainerId());}// Mask layerif(mMaskLayer){layer->set_mask(reinterpret_cast<uint64_t>(mMaskLayer.get()));}// DisplayList log.if(mDisplayListLog.Length()>0){layer->set_displaylistloglength(mDisplayListLog.Length());autocompressedData=MakeUnique<char[]>(LZ4::maxCompressedSize(mDisplayListLog.Length()));intcompressedSize=LZ4::compress((char*)mDisplayListLog.get(),mDisplayListLog.Length(),compressedData.get());layer->set_displaylistlog(compressedData.get(),compressedSize);}}boolLayer::IsBackfaceHidden(){if(GetContentFlags()&CONTENT_BACKFACE_HIDDEN){Layer*container=AsContainerLayer()?this:GetParent();if(container){// The effective transform can include non-preserve-3d parent// transforms, since we don't always require an intermediate.if(container->Extend3DContext()||container->Is3DContextLeaf()){returncontainer->GetEffectiveTransform().IsBackfaceVisible();}returncontainer->GetBaseTransform().IsBackfaceVisible();}}returnfalse;}UniquePtr<LayerUserData>Layer::RemoveUserData(void*aKey){UniquePtr<LayerUserData>d(static_cast<LayerUserData*>(mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));returnd;}voidLayer::SetManager(LayerManager*aManager,HostLayer*aSelf){// No one should be calling this for weird reasons.MOZ_ASSERT(aSelf);MOZ_ASSERT(aSelf->GetLayer()==this);mManager=aManager;}voidPaintedLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){Layer::PrintInfo(aStream,aPrefix);nsIntRegionvalidRegion=GetValidRegion();if(!validRegion.IsEmpty()){AppendToString(aStream,validRegion," [valid=","]");}}voidPaintedLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){Layer::DumpPacket(aPacket,aParent);// get this layer datausingnamespacelayerscope;LayersPacket::Layer*layer=aPacket->mutable_layer(aPacket->layer_size()-1);layer->set_type(LayersPacket::Layer::PaintedLayer);nsIntRegionvalidRegion=GetValidRegion();if(!validRegion.IsEmpty()){DumpRegion(layer->mutable_valid(),validRegion);}}voidContainerLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){Layer::PrintInfo(aStream,aPrefix);if(UseIntermediateSurface()){aStream<<" [usesTmpSurf]";}if(1.0!=mPreXScale||1.0!=mPreYScale){aStream<<nsPrintfCString(" [preScale=%g, %g]",mPreXScale,mPreYScale).get();}if(mScaleToResolution){aStream<<nsPrintfCString(" [presShellResolution=%g]",mPresShellResolution).get();}if(mEventRegionsOverride&EventRegionsOverride::ForceDispatchToContent){aStream<<" [force-dtc]";}if(mEventRegionsOverride&EventRegionsOverride::ForceEmptyHitRegion){aStream<<" [force-ehr]";}}voidContainerLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){Layer::DumpPacket(aPacket,aParent);// Get this layer datausingnamespacelayerscope;LayersPacket::Layer*layer=aPacket->mutable_layer(aPacket->layer_size()-1);layer->set_type(LayersPacket::Layer::ContainerLayer);}voidDisplayItemLayer::EndTransaction(){mItem=nullptr;mBuilder=nullptr;}voidDisplayItemLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){Layer::PrintInfo(aStream,aPrefix);constchar*type="TYPE_UNKNOWN";if(mItem){type=mItem->Name();}aStream<<" [itype type="<<type<<"]";}voidDisplayItemLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){Layer::DumpPacket(aPacket,aParent);// Get this layer datausingnamespacelayerscope;LayersPacket::Layer*layer=aPacket->mutable_layer(aPacket->layer_size()-1);layer->set_type(LayersPacket::Layer::DisplayItemLayer);}voidColorLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){Layer::PrintInfo(aStream,aPrefix);AppendToString(aStream,mColor," [color=","]");AppendToString(aStream,mBounds," [bounds=","]");}voidColorLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){Layer::DumpPacket(aPacket,aParent);// Get this layer datausingnamespacelayerscope;LayersPacket::Layer*layer=aPacket->mutable_layer(aPacket->layer_size()-1);layer->set_type(LayersPacket::Layer::ColorLayer);layer->set_color(mColor.ToABGR());}voidTextLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){Layer::PrintInfo(aStream,aPrefix);AppendToString(aStream,mBounds," [bounds=","]");}voidTextLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){Layer::DumpPacket(aPacket,aParent);// Get this layer datausingnamespacelayerscope;LayersPacket::Layer*layer=aPacket->mutable_layer(aPacket->layer_size()-1);layer->set_type(LayersPacket::Layer::TextLayer);}voidBorderLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){Layer::PrintInfo(aStream,aPrefix);}voidBorderLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){Layer::DumpPacket(aPacket,aParent);}CanvasLayer::CanvasLayer(LayerManager*aManager,void*aImplData):Layer(aManager,aImplData),mPreTransCallback(nullptr),mPreTransCallbackData(nullptr),mPostTransCallback(nullptr),mPostTransCallbackData(nullptr),mSamplingFilter(gfx::SamplingFilter::GOOD),mDirty(false){}CanvasLayer::~CanvasLayer()=default;voidCanvasLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){Layer::PrintInfo(aStream,aPrefix);if(mSamplingFilter!=SamplingFilter::GOOD){AppendToString(aStream,mSamplingFilter," [filter=","]");}}// This help function is used to assign the correct enum value// to the packetstaticvoidDumpFilter(layerscope::LayersPacket::Layer*aLayer,constSamplingFilter&aSamplingFilter){usingnamespacelayerscope;switch(aSamplingFilter){caseSamplingFilter::GOOD:aLayer->set_filter(LayersPacket::Layer::FILTER_GOOD);break;caseSamplingFilter::LINEAR:aLayer->set_filter(LayersPacket::Layer::FILTER_LINEAR);break;caseSamplingFilter::POINT:aLayer->set_filter(LayersPacket::Layer::FILTER_POINT);break;default:// ignore itbreak;}}voidCanvasLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){Layer::DumpPacket(aPacket,aParent);// Get this layer datausingnamespacelayerscope;LayersPacket::Layer*layer=aPacket->mutable_layer(aPacket->layer_size()-1);layer->set_type(LayersPacket::Layer::CanvasLayer);DumpFilter(layer,mSamplingFilter);}voidImageLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){Layer::PrintInfo(aStream,aPrefix);if(mSamplingFilter!=SamplingFilter::GOOD){AppendToString(aStream,mSamplingFilter," [filter=","]");}}voidImageLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){Layer::DumpPacket(aPacket,aParent);// Get this layer datausingnamespacelayerscope;LayersPacket::Layer*layer=aPacket->mutable_layer(aPacket->layer_size()-1);layer->set_type(LayersPacket::Layer::ImageLayer);DumpFilter(layer,mSamplingFilter);}voidRefLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){ContainerLayer::PrintInfo(aStream,aPrefix);if(0!=mId){AppendToString(aStream,mId," [id=","]");}}voidRefLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){Layer::DumpPacket(aPacket,aParent);// Get this layer datausingnamespacelayerscope;LayersPacket::Layer*layer=aPacket->mutable_layer(aPacket->layer_size()-1);layer->set_type(LayersPacket::Layer::RefLayer);layer->set_refid(mId);}voidReadbackLayer::PrintInfo(std::stringstream&aStream,constchar*aPrefix){Layer::PrintInfo(aStream,aPrefix);AppendToString(aStream,mSize," [size=","]");if(mBackgroundLayer){AppendToString(aStream,mBackgroundLayer," [backgroundLayer=","]");AppendToString(aStream,mBackgroundLayerOffset," [backgroundOffset=","]");}elseif(mBackgroundColor.a==1.f){AppendToString(aStream,mBackgroundColor," [backgroundColor=","]");}else{aStream<<" [nobackground]";}}voidReadbackLayer::DumpPacket(layerscope::LayersPacket*aPacket,constvoid*aParent){Layer::DumpPacket(aPacket,aParent);// Get this layer datausingnamespacelayerscope;LayersPacket::Layer*layer=aPacket->mutable_layer(aPacket->layer_size()-1);layer->set_type(LayersPacket::Layer::ReadbackLayer);LayersPacket::Layer::Size*size=layer->mutable_size();size->set_w(mSize.width);size->set_h(mSize.height);}//--------------------------------------------------// LayerManagervoidLayerManager::Dump(std::stringstream&aStream,constchar*aPrefix,boolaDumpHtml,boolaSorted){#ifdef MOZ_DUMP_PAINTINGif(aDumpHtml){aStream<<"<ul><li>";}#endifDumpSelf(aStream,aPrefix,aSorted);nsAutoCStringpfx(aPrefix);pfx+=" ";if(!GetRoot()){aStream<<nsPrintfCString("%s(null)",pfx.get()).get();if(aDumpHtml){aStream<<"</li></ul>";}return;}if(aDumpHtml){aStream<<"<ul>";}GetRoot()->Dump(aStream,pfx.get(),aDumpHtml,aSorted);if(aDumpHtml){aStream<<"</ul></li></ul>";}aStream<<"\n";}voidLayerManager::DumpSelf(std::stringstream&aStream,constchar*aPrefix,boolaSorted){PrintInfo(aStream,aPrefix);aStream<<" --- in "<<(aSorted?"3D-sorted rendering order":"content order");aStream<<"\n";}voidLayerManager::Dump(boolaSorted){std::stringstreamss;Dump(ss,"",false,aSorted);print_stderr(ss);}voidLayerManager::Dump(layerscope::LayersPacket*aPacket){DumpPacket(aPacket);if(GetRoot()){GetRoot()->Dump(aPacket,this);}}voidLayerManager::Log(constchar*aPrefix){if(!IsLogEnabled())return;LogSelf(aPrefix);nsAutoCStringpfx(aPrefix);pfx+=" ";if(!GetRoot()){MOZ_LAYERS_LOG(("%s(null)",pfx.get()));return;}GetRoot()->Log(pfx.get());}voidLayerManager::LogSelf(constchar*aPrefix){nsAutoCStringstr;std::stringstreamss;PrintInfo(ss,aPrefix);MOZ_LAYERS_LOG(("%s",ss.str().c_str()));}voidLayerManager::PrintInfo(std::stringstream&aStream,constchar*aPrefix){aStream<<aPrefix<<nsPrintfCString("%sLayerManager (0x%p)",Name(),this).get();}voidLayerManager::DumpPacket(layerscope::LayersPacket*aPacket){usingnamespacelayerscope;// Add a new layer data (LayerManager)LayersPacket::Layer*layer=aPacket->add_layer();layer->set_type(LayersPacket::Layer::LayerManager);layer->set_ptr(reinterpret_cast<uint64_t>(this));// Layer Tree Rootlayer->set_parentptr(0);}voidLayerManager::TrackDisplayItemLayer(RefPtr<DisplayItemLayer>aLayer){mDisplayItemLayers.AppendElement(aLayer);}voidLayerManager::ClearDisplayItemLayers(){for(uint32_ti=0;i<mDisplayItemLayers.Length();i++){mDisplayItemLayers[i]->EndTransaction();}mDisplayItemLayers.Clear();}/*static*/boolLayerManager::IsLogEnabled(){returnMOZ_LOG_TEST(GetLog(),LogLevel::Debug);}voidLayerManager::SetPendingScrollUpdateForNextTransaction(FrameMetrics::ViewIDaScrollId,constScrollUpdateInfo&aUpdateInfo){mPendingScrollUpdates[aScrollId]=aUpdateInfo;}Maybe<ScrollUpdateInfo>LayerManager::GetPendingScrollInfoUpdate(FrameMetrics::ViewIDaScrollId){autoit=mPendingScrollUpdates.find(aScrollId);if(it!=mPendingScrollUpdates.end()){returnSome(it->second);}returnNothing();}voidLayerManager::ClearPendingScrollInfoUpdate(){mPendingScrollUpdates.clear();}voidPrintInfo(std::stringstream&aStream,HostLayer*aLayerComposite){if(!aLayerComposite){return;}if(constMaybe<ParentLayerIntRect>&clipRect=aLayerComposite->GetShadowClipRect()){AppendToString(aStream,*clipRect," [shadow-clip=","]");}if(!aLayerComposite->GetShadowBaseTransform().IsIdentity()){AppendToString(aStream,aLayerComposite->GetShadowBaseTransform()," [shadow-transform=","]");}if(!aLayerComposite->GetShadowVisibleRegion().IsEmpty()){AppendToString(aStream,aLayerComposite->GetShadowVisibleRegion().ToUnknownRegion()," [shadow-visible=","]");}}voidSetAntialiasingFlags(Layer*aLayer,DrawTarget*aTarget){boolpermitSubpixelAA=!(aLayer->GetContentFlags()&Layer::CONTENT_DISABLE_SUBPIXEL_AA);if(aTarget->IsCurrentGroupOpaque()){aTarget->SetPermitSubpixelAA(permitSubpixelAA);return;}constIntRect&bounds=aLayer->GetVisibleRegion().ToUnknownRegion().GetBounds();gfx::RecttransformedBounds=aTarget->GetTransform().TransformBounds(gfx::Rect(Float(bounds.x),Float(bounds.y),Float(bounds.width),Float(bounds.height)));transformedBounds.RoundOut();IntRectintTransformedBounds;transformedBounds.ToIntRect(&intTransformedBounds);permitSubpixelAA&=!(aLayer->GetContentFlags()&Layer::CONTENT_COMPONENT_ALPHA)||aTarget->GetOpaqueRect().Contains(intTransformedBounds);aTarget->SetPermitSubpixelAA(permitSubpixelAA);}IntRectToOutsideIntRect(constgfxRect&aRect){returnIntRect::RoundOut(aRect.x,aRect.y,aRect.width,aRect.height);}TextLayer::TextLayer(LayerManager*aManager,void*aImplData):Layer(aManager,aImplData){}TextLayer::~TextLayer(){}voidTextLayer::SetGlyphs(nsTArray<GlyphArray>&&aGlyphs){MOZ_LAYERS_LOG_IF_SHADOWABLE(this,("Layer::Mutated(%p) Glyphs",this));mGlyphs=Move(aGlyphs);Mutated();}}// namespace layers}// namespace mozilla